package channel

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/linclaus/stock/pkg/alertmanager"
	"github.com/linclaus/stock/pkg/api"
	"github.com/linclaus/stock/pkg/cache"
	"github.com/linclaus/stock/pkg/gografana"
	"github.com/linclaus/stock/pkg/grafana"
	"github.com/linclaus/stock/pkg/model"
	"github.com/linclaus/stock/pkg/prometheus"
)

var lock sync.RWMutex

func Init() {
	go monitorStockAdd(cache.StockMap.StockAddChan)
	go monitorStrategyAdd(cache.StrategyAddChan)
	go monitorStrategyDelete(cache.StrategyDeleteChan)
	go monitorGrafanaRendererSave(cache.GrafanaRendererChan)
}

// Add custom monitor handler
func monitorStockAdd(stock chan model.Stock) {
	for s := range stock {
		handlerStock(s)
	}
}

func handlerStock(stock model.Stock) {}

func monitorStrategyAdd(strategy chan model.Strategy) {
	for s := range strategy {
		handlerStrategyAdd(s)
	}
}
func handlerStrategyAdd(strategy model.Strategy) {
	lock.Lock()
	defer lock.Unlock()
	if sb, err := json.Marshal(strategy); err == nil {
		fmt.Printf("Create or Update Strategy: %s\n", string(sb))
	}

	if err := prometheus.GenerateRuleAndWriteFile(strategy); err != nil {
		fmt.Printf("Code:%s update prometheus rule failed for reason:%s\n", strategy.Code, err)
	}
	if err := alertmanager.AddAlertmanagerStrategy(strategy); err != nil {
		fmt.Printf("Code:%s update alertmanager failed for reason:%s\n", strategy.Code, err)
	}
}

func monitorStrategyDelete(strategy chan model.Strategy) {
	for s := range strategy {
		handlerStrategyDelete(s)
	}
}
func handlerStrategyDelete(strategy model.Strategy) {
	lock.Lock()
	defer lock.Unlock()
	if sb, err := json.Marshal(strategy); err == nil {
		fmt.Printf("Delete Strategy: %s\n", string(sb))
	}

	if err := prometheus.DeleteRuleAndWriteFile(strategy); err != nil {
		fmt.Printf("Code:%s delete prometheus rule failed for reason:%s\n", strategy.Code, err)
	}
	if err := alertmanager.DeleteAlertmanagerStrategy(strategy); err != nil {
		fmt.Printf("Code:%s delete alertmanager failed for reason:%s\n", strategy.Code, err)
	}
}

func monitorGrafanaRendererSave(board chan gografana.Board) {
	for b := range board {
		handlerGrafanaRendererSave(b)
	}
}

func handlerGrafanaRendererSave(board gografana.Board) {
	t := time.Now()
	if t.Hour() < 9 || (t.Hour() == 9 && t.Minute() < 30) {
		t.AddDate(0, 0, -1)
	}
	from := time.Date(t.Year(), t.Month(), t.Day(), 9, 30, 0, 0, t.Location())
	to := time.Date(t.Year(), t.Month(), t.Day(), 15, 00, 0, 0, t.Location())
	url := fmt.Sprintf("%s/render%s?orgId=1&from=%d000&to=%d000&panelId=1&width=1000&height=500&tz=%s", grafana.GrafanaArgs.GrafanaAddr, board.Url, from.Unix(), to.Unix(), "Asia%2FShanghai")
	url = strings.Replace(url, "/d/", "/d-solo/", 1)
	fmt.Printf("render url: %s", url)
	var client = http.Client{}
	req, err := http.NewRequest("GET", url, nil)
	req.Header.Add("Accept", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("http.Get -> %v\n", err)
		return
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("ioutil.ReadAll -> %v\n", err)
		return
	}

	defer resp.Body.Close()
	imagePath := fmt.Sprintf("%spng/%s", api.STOCK_FILE_PATH, board.Title+".png")
	fmt.Printf("save image to path: %s\n", imagePath)
	err = ioutil.WriteFile(imagePath, data, 0666)
	if err != nil {
		fmt.Printf("ioutil.WriteFile -> %v\n", err)
		return
	}
}
